<?php

namespace App;

use Doctrine\Common\Annotations\AnnotationReader;

/**
 * Class ClassScanner
 * @auth: kingofzihua
 * @package App
 */
class ClassScanner
{
    /**
     * @auth: kingofzihua
     * @var object
     */
    public $class;

    /**
     * @auth: kingofzihua
     * @var \ReflectionClass
     */
    public $oReflectionClass;

    /**
     * ClassScanner constructor.
     * @param $className
     * @throws \Exception
     * @throws \ReflectionException
     */
    public function __construct($className)
    {
        if (!class_exists($className)) {
            throw new \Exception($className . '类不存在');
        }

        //获取反射类
        $this->oReflectionClass = $oReflectionClass = new \ReflectionClass($className);

        if (!$oReflectionClass->isInstantiable()) {
            throw new \Exception($className . '类不能实例化');
        }

        //获取构造函数
        $constructor = $oReflectionClass->getConstructor();

        if ($constructor == null) {//没有构造函数
            $this->class = $oReflectionClass->newInstance();
            return;
        }

        //获取构造函数的参数
        if (empty($constructor->getParameters())) {//参数为空

            $this->class = $oReflectionClass->newInstance();
            return;
        }

        throw new \Exception($className . '初始化参数不为空，获取失败');

    }

    /**
     * 自动注入
     * @auth: kingofzihua
     * @return object
     * @throws \Doctrine\Common\Annotations\AnnotationException
     */
    public function autoInject()
    {
        //获取类里面的class
        if (!$class = $this->class) {
            new \Exception('当前类未被实例化');
        }

        //获取反射的类所有的属性
        $properties = $this->oReflectionClass->getProperties();

        /**
         * 遍历所有的属性
         */
        foreach ($properties as $property) {
            //处理每个属性
            $this->propertyHandle($property);
        }

        return $this->class;
    }

    /**
     * @auth: kingofzihua
     * @param $property
     * @throws \Doctrine\Common\Annotations\AnnotationException
     */
    public function propertyHandle($property)
    {
        //通过参数名获取注释
        $class = $this->getCommentByName($property->getName());

        // 判断$class是否是一个类, 如果是类并且是不是闭包函数的话，就说明是一个对象
        if (get_class($class) && !is_callable($class)) {
            $this->class->{$property->getName()} = $class;
        }
    }

    /**
     * @auth: kingofzihua
     * @param $name
     * @return mixed
     * @throws \Doctrine\Common\Annotations\AnnotationException
     */
    public function getCommentByName($name)
    {
        //通过反射获取参数
        $property = $this->oReflectionClass->getProperty($name);

        $reader = new AnnotationReader();

        //获取处理后的注释
        $myAnnotation = $reader->getPropertyAnnotations($property);

        foreach ($myAnnotation as $item) {
            if (method_exists($item, 'getClass')) {
                return $item->getClass();
            }
        }
    }
}
